路遙知碼力,日久練成精-只要在程式之路鑽研的夠深,便能夠充分發揮程式碼的力量; 練習的日子夠久,便能夠練成寫出精簡代碼的能力。
首先公佈昨天課後練習解答:
(還沒看過題目的朋友歡迎點昨日題目傳送門)
def findMin(N, W):
return min([min(w) for w in W])
min()函數無法直接取得二維list的最小值,
所以你可以這樣做,
用列表生成式取得每列list的最小值再取整體的最小值,
你答對了嗎?
(其實參數N是可以不用的,別被題目誤導囉)
大家好,今天進入「列表生成式」語法第二招囉。
除了昨天說的可以單純用一個列表生成另一個新列表之外,
有時候我們會想要取出列表內滿足條件的元素,
而非取出所有元素,
這時可以直接在「列表生成式」後面加上if語句,
決定篩選的條件。
語法大致上如下:
新列表 = [something for x in 舊列表(或可迭代物件) if 條件判斷句]
直接看幾個例子比較容易理解。
>>> L=[18, 73, -24, 6, 34, -87, -17, -98, -53, 16]
>>> [x for x in L if x%2==0]
[18, -24, 6, 34, -98, 16]
>>> [x for x in L if x<0]
[-24, -87, -17, -98, -53]
(註: 內建函數isinstance(x, type)可以判斷前者是否為後者的變數型態)
>>> M = ["Horse","Tiger",25,6.2,"Tomato"]
>>> [x for x in M if isinstance(x, str)]
['Horse', 'Tiger', 'Tomato']
還記得我們在Day7- 如果你願意一層一層一層 的剝開繁瑣邏輯這篇中教過如何化簡if-else嗎?
這邊快速的幫大家複習一下:
當我們用if-else語句時,
普通的寫法表達為:
if 條件成立:
變數= 值1
else:
變數= 值2
必須要寫四行,實在有點繁瑣。
從前人「一目十行」,
形容人的閱讀速度很快。
現代人「螢幕十行」,
形容電腦螢幕太小,
程式碼行數太多都要上下捲動螢幕才能看到完整的程式碼。
還好在python中可以將if-else濃縮成一行,
程式語法可以簡化為:
變數 = 值1 if 條件成立 else值2
舉例來說,當我們想要判斷使用者輸入的數字是否為3的倍數,
我們便可以這樣寫:
num = int(input())
print(f"{num} 是 3 的倍數" if num % 3 ==0 else f"{num} 不是 3 的倍數")
注意使用三元運算子語法時,if-else一定要成對出現。
如果是加在列表生成式for迴圈後面的if語句則不會有else出現。
緊接著看幾個應用幫助了解使用情境吧。
阿明的女朋友生日要到了,
阿明決定到蛋糕店買兩個小蛋糕給女朋友慶生,
給定一個陣列表示所有可以買的蛋糕價格。
為了表達滿滿的心意。
阿明希望買的蛋糕總價格愈高愈好,
但由於阿明還是學生,打工收入不高,預算有限。
請幫阿明計算他在不超過預算的前提下,
可以買到的兩個小蛋糕價錢最高為何?
請實作函數 mostValue(nums, K)
,
參數nums
代表所有可以購買的蛋糕價錢(一定全是正整數),
參數K
是一個正整數代表阿明的預算。
回傳陣列兩個數的最大總和但要小於K。
(如果買不起蛋糕則回傳 -1
)
nums = [100,200,500,2000]
K = 1000
Output: 700
例子1表示店內有賣100,200,500,2000元的蛋糕各一個,
但阿明預算只有1000元,
故最高只能買200+500=700元的蛋糕。
(注意不能買2個500元的蛋糕,因為500元的蛋糕只有一個。)
nums = [100,200,500,2000]
K = 200
Output: -1
例子2表示店內有賣100,200,500,2000元的蛋糕各一個,
但阿明預算只有200元,
阿明是買不起兩個蛋糕的,故函數應回傳 -1。
函數實作如下:
def mostValue(nums, K):
L=[nums[i]+nums[j] for i in range(len(nums)) for j in range(i+1,len(nums)) if nums[i]+nums[j]<=K]
return max(L) if len(L)>0 else -1
函數內第一行表示窮舉陣列所有相異索引(index)的兩個數相加,
並過濾出所有不超出預算的金額。
第二行運用了三元運算子,
如果L不為空陣列(即阿明買的起兩個蛋糕),
回傳最高的金額,
否則回傳 -1。
利用以下程式進行測試:
測試程式如下:
nums = [100,200,500,2000]
print(mostValue(nums, 1000))
print(mostValue(nums, 200))
結果印出700
-1
是我們要的預期結果。
給定一個列表表示班上同學的分數,
例如:
scores = [20,30,50,60,25,70]
希望把每個人的分數換算成是否及格的結果,
期望結果: ['需要重修', '需要重修', '需要重修', '及格', '需要重修', '及格']
。
若分數在60分以上,換成「及格」字串,
否則換成「需要重修」字串。
其實這是三元運算子在列表生成式中的運用,
程式如下:
scores = [20,30,50,60,25,70]
passed = ["及格" if s>=60 else "需要重修" for s in scores]
print(passed) #['需要重修', '需要重修', '需要重修', '及格', '需要重修', '及格']
質數(prime) 是只能被1和自己兩個數整除的正整數 (注意1不算質數)。
判斷一個數是否是質數是數學上的經典問題,
也是程式設計課常常拿來做為入門的一個問題。
但大概少有程式語言能寫的像python一樣精簡的吧?
我們希望實作一個判斷質數的函數:
def isPrime(n):
pass
輸入n是一個正整數,
如果n是質數,函數回傳True
;
如果n不是質數,函數回傳False
。
目前我想到兩種簡潔的語法來做,
各自練習到在列表生成式後加上if判斷條件,
以及三元運算子應用在列表中兩種情況,
就看大家比較喜歡哪一種囉。
第一種方法,
可以檢查所有在1~n的數字,
如果該數字可以整除n的話,
就存在列表中。
例如6的因數有1,2,3,6,
我們希望得到一張列表[1,2,3,6]。
由於質數表示恰好有兩個因數,
只要檢查這個列表是否恰有兩個元素即可。
程式碼如下:
def isPrime(n):
return len([i for i in range(1,n+1) if n%i==0])==2
解法二同樣去檢查所有在1~n的數字,
但是我們存一張長度為n的列表,
如果該數字可以整除n的話,
列表的對應位置為1,否則為0。
例如6的因數有1,2,3,6,
我們希望得到一張列表[1,1,1,0,0,1],
表示6可以被1, 2, 3, 6整除,
但不能被4, 5整除。
只要檢查這個列表的總和是否為2,
即知道n是否恰好有兩個因數。
程式碼如下:
def isPrime(n):
return sum([1 if n%i==0 else 0 for i in range(1,n+1)])==2
可以簡單測試一下程式:
for i in range(1,10):
print(f'{i}是質數?: {isPrime(i)}')
結果為:
1是質數?: False
2是質數?: True
3是質數?: True
4是質數?: False
5是質數?: True
6是質數?: False
7是質數?: True
8是質數?: False
9是質數?: False
結果正確。
但是目前解法一,二都有個待改善的問題: 效率不佳。
譬如說你在你的電腦上用這兩個解法測一下10的8次方(即一億)是否為質數:
print(isPrime(10 ** 8))
估計沒有跑個好幾秒應該是跑不出結果的。
(時間因電腦效能而異,跑個好幾十秒可能也是正常的)
為什麼我們認為算法效率不佳呢?
因為一億這個數是一個偶數呀,
當我們檢查到一億可以被2整除時,
一億就不可能是質數了,
接下來是不需要再把3到一億這麼大量的數檢查完才能判斷的。
那麼如何提升判斷質數的效率呢?
除了你可能想的到的用while-break語法的語法來解,
在檢查到一億可以被2整除時提早跳出迴圈。
我們還有python風格的語法,
同時兼顧執行效率又維持精簡的程式,
預計在後續篇章談到any(), all()函數時會探討到,敬請期待。
你好
def mostValue(nums, K):
L=[nums[i]+nums[j] for i in range(len(nums)) for j in range(i+1,len(nums)) if nums[i]+nums[j]<=K]
return max(L) if len(L)>0 else -1
nums = [100,200,500,2000]
print(mostValue(nums, 1000))
print(mostValue(nums, 200))
我不太懂這裡 for j in range(i+1,len(nums))
for i in range(len(nums)) 在這裡 i = 0,1,2,3
那 j 是= 什麼? i+1 是指 0+1, 1+1, 2+1, 3+1嗎? 另外第2個參數為什麼是len(nums)? 謝謝
您好,想請問課後練習題目,我的解答如下,會有可能產生其他答案上的錯誤嗎?
def findMin(N, W):
return min(min(W[:]))
if __name__ == '__main__':
print(findMin(N=2, W=[[740, 516, 725, 718, 861, 634, 723],
[914, 747, 580, 593, 722, 877, 595]]))